package org.appfuse.webapp.action;

import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.navigator.menu.MenuComponent;
import net.sf.navigator.menu.MenuRepository;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.appfuse.Constants;
import org.appfuse.model.BasicInfo;
import org.appfuse.model.Bj77;
import org.appfuse.model.Criteria;
import org.appfuse.model.Menu;
import org.appfuse.model.User;
import org.appfuse.service.BasicInfoManager;
import org.appfuse.service.Bj77Manager;
import org.appfuse.service.CriteriaManager;
import org.appfuse.service.MenuManager;
import org.appfuse.service.UserManager;
import org.appfuse.webapp.form.MenuForm;

/**
 * Action class to handle CRUD on a Menu object
 * 
 * @struts.action name="menuForm" path="/menus" scope="request" validate="false"
 *                parameter="method" input="mainMenu"
 * @struts.action name="menuForm" path="/editMenu" scope="request"
 *                validate="false" parameter="method" input="list"
 * @struts.action name="menuForm" path="/saveMenu" scope="request"
 *                validate="true" parameter="method" input="edit"
 * @struts.action-set-property property="cancellable" value="true"
 * @struts.action-forward name="edit" path="/WEB-INF/pages/menuForm.jsp"
 * @struts.action-forward name="list" path="/WEB-INF/pages/menuList.jsp"
 * @struts.action-forward name="search" path="/menus.html" redirect="true"
 */
public final class MenuAction extends BaseAction {

	protected final static String DEFAULT_TOP_CRITERIA_PATTERN = "000000";

	protected static MenuComponent DEFAULT_TOP_MENU = null;

	protected static boolean IS_INITIALED = false;

	protected static MenuRepository MENU_REPOSITORY = null;
	
	static {
		DEFAULT_TOP_MENU = new MenuComponent();
		DEFAULT_TOP_MENU.setName(Constants.DEFAULT_TOP_MENU_NAME);
	}

	public ActionForward cancel(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		return mapping.findForward("search");
	}

	public ActionForward delete(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'delete' method");
		}

		ActionMessages messages = new ActionMessages();
		MenuForm menuForm = (MenuForm) form;

		// Exceptions are caught by ActionExceptionHandler
		MenuManager mgr = (MenuManager) getBean("menuManager");
		mgr.removeMenu(String.valueOf(menuForm.getId()));

		messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
				"menu.deleted"));

		// save messages in session, so they'll survive the redirect
		saveMessages(request.getSession(), messages);

		return mapping.findForward("search");
	}

	public ActionForward edit(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'edit' method");
		}

		MenuForm menuForm = (MenuForm) form;

		// if an id is passed in, look up the user - otherwise
		// don't do anything - user is doing an add
		if (menuForm.getId() != null) {
			MenuManager mgr = (MenuManager) getBean("menuManager");
			Menu menu = mgr.getMenu(String.valueOf(menuForm.getId()));
			menuForm = (MenuForm) convert(menu);
			updateFormBean(mapping, request, menuForm);
		}

		return mapping.findForward("edit");
	}

	public ActionForward save(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'save' method");
		}

		// Extract attributes and parameters we will need
		ActionMessages messages = new ActionMessages();
		MenuForm menuForm = (MenuForm) form;
		boolean isNew = ("".equals(menuForm.getId()) || menuForm.getId() == null);

		MenuManager mgr = (MenuManager) getBean("menuManager");
		Menu menu = (Menu) convert(menuForm);
		mgr.saveMenu(menu);

		// add success messages
		if (isNew) {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"menu.added"));

			// save messages in session to survive a redirect
			saveMessages(request.getSession(), messages);
			if (IS_INITIALED == false) {
				populateRepository(request);
			}
			request.setAttribute("isNew", "true");
			return mapping.findForward("list");
		} else {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"menu.updated"));
			saveMessages(request, messages);

			return mapping.findForward("edit");
		}
	}

	public ActionForward list(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'search' method");
		}
//
//		String name = request.getParameter("name");
//		MenuForm menuForm = (MenuForm) form;
//		Menu menu = (Menu) convert(menuForm);

		// populate menu
		if (IS_INITIALED == false) {
			initRepository(request);
		}
		
		//set current user to session
		HttpSession session = request.getSession();
		User user = (User) session.getAttribute(Constants.CURRENT_USER);
		UserManager userMgr = (UserManager) getBean(Constants.USER_MANAGER);
		if (user == null){
			String username = request.getRemoteUser();
			
			user = userMgr.getUserByUsername(username);
		
			session.setAttribute(Constants.CURRENT_USER, user);
		}
		try{
		if (StringUtils.isEmpty(user.getRecordId())){
			BasicInfoManager basicInfoMgr = (BasicInfoManager) getBean(Constants.BASICINFO_MANAGER);
			BasicInfo basicInfo = new BasicInfo();
			Bj77Manager bj77Mgr = (Bj77Manager) getBean(Constants.BJ77_MANAGER);
			List bj77s = bj77Mgr.findAll();
			Iterator it = bj77s.iterator();
			while (it.hasNext()){
				Bj77 tmp = (Bj77) it.next();
				
			}
			basicInfo.getBj77s().addAll(bj77s);
			basicInfoMgr.save(basicInfo);

			user.setRecordId(basicInfo.getId());
			userMgr.saveUser(user);
		}else{
			BasicInfoManager basicInfoMgr = (BasicInfoManager) getBean(Constants.BASICINFO_MANAGER);
			BasicInfo basicInfo = basicInfoMgr.findById(user.getRecordId());
			if (basicInfo == null){
				basicInfo = new BasicInfo();
				Bj77Manager bj77Mgr = (Bj77Manager) getBean(Constants.BJ77_MANAGER);
				List bj77s = bj77Mgr.findAll();
				basicInfo.getBj77s().addAll(bj77s);
				basicInfoMgr.save(basicInfo);
				user.setRecordId(basicInfo.getId());
				userMgr.saveUser(user);
			}
		}
		}catch (Exception e){
			e.printStackTrace();
		}
		
		return mapping.findForward("list");
	}

	public ActionForward getSubMenu(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'search' method");
		}

		MenuForm menuForm = (MenuForm) form;
		Menu menu = (Menu) convert(menuForm);

		String name = request.getParameter("name");
		Menu m = new Menu();
		m.setName(name);
		MenuManager mgr = (MenuManager) getBean("menuManager");
		List menus = mgr.getMenus(menu);
		request.setAttribute(Constants.MENU_LIST, mgr.getMenus(menu));
		return mapping.findForward("subMenuList");
	}

	public ActionForward unspecified(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		return list(mapping, form, request, response);
	}
	
	protected void initRepository(HttpServletRequest request){
		populateRepository(request);
	//	addContentToRepository(request);
		//IS_INITIALED = true;
	}

	protected void populateRepository(HttpServletRequest request) {

		// populate menu skelecton
		MENU_REPOSITORY = (MenuRepository) request.getSession()
				.getServletContext().getAttribute(
						Constants.MENU_REPOSITORY_KEY);
		MENU_REPOSITORY.removeAllMenus();
		
		MenuManager mgr = (MenuManager) getBean("menuManager");
		List menuList = mgr.getMenus(null);
		for (Iterator it = menuList.iterator(); it.hasNext();) {
			Menu m = (Menu) it.next();
			MenuComponent mc = new MenuComponent();
			
			//initial mc with m
			try {
				BeanUtils.copyProperties(mc, m);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				if (log.isDebugEnabled()) {
					log.debug("copy properties from menu dao to menu component failed.");
				}
				continue;
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				if (log.isDebugEnabled()) {
					log.debug("copy properties from menu dao to menu component failed.");
				}
				continue;
			}
			
			//set parent menu of new menu component.
			String p = m.getParentName();
			if (p != null) {
				MenuComponent parentMenu = MENU_REPOSITORY.getMenu(p);
				if (parentMenu == null) {
				//	System.out.println("parentMenu '" + p + "' doesn't exist!");
					parentMenu = new MenuComponent();
					parentMenu.setName(p);
					MENU_REPOSITORY.addMenu(parentMenu);
				}
				mc.setParent(parentMenu);
			}


			//set location to a full url
			String path = getRequestPath(request);
			String location = m.getLocation();
			if (StringUtils.isEmpty(location)){
				location = Constants.DEFAULT_LOCATION;
			}
			mc.setLocation(path + "/" + location);
			MENU_REPOSITORY.addMenu(mc);
		}

	}

	protected void addContentToRepository(HttpServletRequest request) {

		CriteriaManager cmgr = (CriteriaManager) getBean("criteriaManager");
		List criteriaList = cmgr.getAllCriterias();

		for (Iterator it = criteriaList.iterator(); it.hasNext();) {
			Criteria criteria = (Criteria) it.next();
						
			//skip leaf menu.
			if (isLeafCriteria(criteria)){
				continue;
			}
			
			MenuComponent mc = new MenuComponent();
			String criteriaNumber = criteria.getCriteriaNumber();
			criteriaNumber = addCriteriaPrefix(criteriaNumber);
			mc.setName(criteriaNumber);
			String parentNumber = criteria.getParentNumber();
			
			if (parentNumber != null) {
				parentNumber = addCriteriaPrefix(parentNumber);
				MenuComponent parentMenu = MENU_REPOSITORY.getMenu(parentNumber);
				if (parentMenu == null) {
					parentMenu = new MenuComponent();
					parentMenu.setName(parentNumber);
					MENU_REPOSITORY.addMenu(parentMenu);
				}
				mc.setParent(parentMenu);
			} else {
				
				MenuComponent parentMenu = MENU_REPOSITORY.getMenu(Constants.DEFAULT_TOP_MENU_NAME);
				if (parentMenu == null) {
					parentMenu = new MenuComponent();
					parentMenu.setName(parentNumber);
					MENU_REPOSITORY.addMenu(parentMenu);
				}
				mc.setParent(parentMenu);
			}
			String title = criteria.getTitle();
			mc.setTitle(title);
			String path = getRequestPath(request);
			// String location = criteria.getLocation();
			String location = Constants.DEFAULT_LOCATION;
//			 if (StringUtils.isEmpty(location)){
//				 location = Constants.DEFAULT_LOCATION;
//			 }
//			String location = Constants.DEFAULT_LOCATION;
//			int index = request.getRequestURL().lastIndexOf("/");
//			path = path.substring(0, index);
			mc.setLocation(path + "/" + location + "&name=" + criteriaNumber);
			MENU_REPOSITORY.addMenu(mc);
		}
	}

	protected boolean isTopCriteria(Criteria criteria) {
		if (criteria == null) {
			return false;
		}

		return criteria.getCriteriaNumber().endsWith("000000");
	}
	
	protected boolean isLeafCriteria(Criteria criteria){
		if (criteria == null || criteria.getCriteriaNumber() == null){
			return true;
		}
		
		return !criteria.getCriteriaNumber().endsWith("00");
	}
	
	protected String addCriteriaPrefix(String criteriaNumber){
		if (StringUtils.isBlank(criteriaNumber) || criteriaNumber.startsWith(Constants.CRITERIA_NAME_PREFIX)){
			return criteriaNumber;
		}
		return Constants.CRITERIA_NAME_PREFIX + criteriaNumber;
	}
	
	protected String removeCriteriaPrefix(String criteriaNumber){
		if (StringUtils.isBlank(criteriaNumber) || !criteriaNumber.startsWith(Constants.CRITERIA_NAME_PREFIX)){
			return criteriaNumber;
		}
		return StringUtils.remove(criteriaNumber, Constants.CRITERIA_NAME_PREFIX);
	}
	
	protected String getRequestPath(HttpServletRequest request){
		String path = new String(request.getRequestURL());
		if (!StringUtils.isEmpty(path)){
			int index = request.getRequestURL().lastIndexOf("/");
			path = path.substring(0, index);
		}
		return path;
	}
}
